package ar.com.temporis.manufacturing.domain;

import java.util.Collection;
import java.util.Date;
import java.util.List;

import ar.com.temporis.framework.common.Observable;
import ar.com.temporis.framework.common.Observer;
import ar.com.temporis.framework.domain.Entity;
import ar.com.temporis.system.domain.User;
import ar.com.temporis.util.collection.CollectionFactory;

/**
 * 
 * @author matias
 * 
 */
public class WorkOrder extends Entity implements Observable {

	private WorkOrderState workOrderState;
	private Collection<Request> requests = CollectionFactory.createCollection();
	private List<WorkOrderRecord> records = CollectionFactory.createList();
	
	private Date creationDate;
	private Date dueDate;

	// keep it transient... do not include it in hibernate's mappings
	private Collection<Observer> observers = CollectionFactory.createCollection();
	
	public Date getCreationDate() {
		return creationDate;
	}

	public void setCreationDate(Date creationDate) {
		this.creationDate = creationDate;
	}

	public Date getDueDate() {
		return dueDate;
	}

	public void setDueDate(Date dueDate) {
		this.dueDate = dueDate;
	}

	public WorkOrderState getWorkOrderState() {
		return workOrderState;
	}
	
	public void setWorkOrderState(WorkOrderState workOrderState) {
		this.workOrderState = workOrderState;
	}

	public Collection<Request> getRequests() {
		return requests;
	}

	public WorkOrder addRequest(Request request) {
		this.requests.add(request);
		return this;
	}

	public List<WorkOrderRecord> getRecords() {
		return records;
	}

	public void setRecords(List<WorkOrderRecord> records) {
		this.records = records;
	}

	public void setRequests(Collection<Request> requests) {
		this.requests = requests;
	}

	public void accept(Observer observer) {
		this.observers.add(observer);
	}

	public void remove(Observer observer) {
		this.observers.remove(observer);
	}

	private void notifyObservers(Object object) {
		for (Observer observer : this.observers) {
			observer.update(this, object);
		}
	}

	/**
	 * set {@link WorkOrder}'s state as closed. It happens when a {@link WorkOrder}
	 * is finished.
	 * 
	 * @param user
	 *            who changed the {@link WorkOrder}'s state.
	 * @return this
	 */
	public WorkOrder closeTicket(User user) {
		this.setWorkOrderState(WorkOrderState.CLOSED);

		selfAudition(user);

		return this;
	}
	
	/**
	 * set {@link WorkOrder}'s state as "Rejected". It happens when is something
	 * wrong with a {@link WorkOrder}'s {@link Request}.
	 * 
	 * @param user
	 *            who changed the {@link WorkOrder}'s state.
	 * @return this
	 */
	public WorkOrder rejectTicket(User user) {
		this.setWorkOrderState(WorkOrderState.REJECTED);

		selfAudition(user);

		return this;
	}
	
	/**
	 * set {@link WorkOrder}'s state as "Approved". It happens when a
	 * {@link WorkOrder} gets in the Manufacturing Process.
	 * 
	 * @param user
	 *            who changed the {@link WorkOrder}'s state.
	 * @return this
	 */
	public WorkOrder approveWorkOrder(User user) {
		this.setWorkOrderState(WorkOrderState.APPROVED);

		selfAudition(user);

		return this;
	}

	/**
	 * This is not a common audition. We want to notify UI users, the main idea
	 * is to add an observer and notify it about state changes. Then, this
	 * obverver will initiate the process for showing alarms, new states, etc.
	 * 
	 * @param user
	 */
	private void selfAudition(User user) {
		WorkOrderRecord record = new WorkOrderRecord();
		
		record.setDate(new Date());
		record.setUser(user);
		record.setState(this.getWorkOrderState());

		this.addTicketRecord(record);
		this.notifyObservers(this.getWorkOrderState());
	}

	public WorkOrder addTicketRecord(WorkOrderRecord record) {
		this.records.add(record);
		return this;
	}

}
